package com.chenfan.mcn.mq.producer;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chenfan.mcn.clients.privilege.PrivilegeClient;
import com.chenfan.mcn.clients.privilege.SUserVo;
import com.chenfan.mcn.constant.NumberCst;
import com.chenfan.mcn.dao.*;
import com.chenfan.mcn.enums.*;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.mcn.model.*;
import com.chenfan.mcn.mq.AbstractMessageProducer;
import com.chenfan.mcn.mq.MessageProducer;
import com.chenfan.mcn.mq.message.ChargeAutoInvoiceMessage;
import com.chenfan.mcn.mq.message.CfChargeCommonMessage;
import com.chenfan.mcn.utils.BusinessAssert;
import com.chenfan.mcn.utils.CommonUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

/**
 * @author: tangwei
 * Date:     2021/3/3 10:36
 * Description: 执行单费用推送财务系统
 * <p>
 * 红人分成费
 * <p>
 * 红人采购费
 * <p>
 * 如果执行单【AE确认客户返点金额】大于0，则生成客户返点费用。
 */

@Slf4j
@Service
public class ExcutionOrderMessageProducer extends AbstractMessageProducer implements MessageProducer<Long> {

    @Autowired
    private ContractExcutionOrderMapper contractExcutionOrderMapper;

    @Autowired
    private CalculationDevidedMapper calculationDevidedMapper;

    @Autowired
    private IncomeContractMapper incomeContractMapper;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Autowired
    private StarBasicDataMapper starBasicDataMapper;

    @Async
    @Override
    public void asyncSendRecordToMq(Long excutionOrderId) {
        log.info("进入执行单生成费用推送MQ方法==》excutionOrderId={}", excutionOrderId);
        ContractExcutionOrder excutionOrder = contractExcutionOrderMapper.selectById(excutionOrderId);
        BusinessAssert.notNull(excutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
        IncomeContract incomeContract = incomeContractMapper.selectById(excutionOrder.getIncomeContractId());
        BusinessAssert.notNull(incomeContract, McnErrorCode.INCOME_NOT_EXISTS);
        StarBasicData starBasicData = starBasicDataMapper.selectById(excutionOrder.getStarId());
        BusinessAssert.notNull(starBasicData, McnErrorCode.DATA_NOT_FOUND, "查询不到该红人");
        CalculationDevided calculationDevided = calculationDevidedMapper.getByExecuteId(excutionOrderId);
        List<String> userList = Collections.singletonList(excutionOrder.getExcutorName());
        Map<String, SUserVo> userMapping = Objects.requireNonNull(privilegeClient.getUserIdsByName(userList)).getObj();
        List<CfChargeCommonMessage> chargeList = new ArrayList<>();
        List<ChargeAutoInvoiceMessage> invoiceList = new ArrayList<>();
        if (SettlementMethodEnum.isSingleRemittance(calculationDevided.getSettlementMethod()) && CommonUtil.greaterThanZero(calculationDevided.getFinanceDevidedAmount())) {
            CfChargeCommonMessage chargeMessage;
            if (StrUtil.isBlank(excutionOrder.getPurchaseCode())) {
                /** 红人分成费 */
                chargeMessage = this.buildStarDevidedFee(excutionOrder, incomeContract, calculationDevided, starBasicData);

            } else {
                /** 红人采购费 */
                chargeMessage = this.buildStarPurchaseFee(excutionOrder, incomeContract, calculationDevided, starBasicData);
            }
            this.fillDataScopeInfo(chargeMessage, excutionOrder, userMapping);
            invoiceList.add(this.buildAutoInvoiceMessage(excutionOrder, chargeMessage));
        } else if (SettlementMethodEnum.isReceivePayment(calculationDevided.getSettlementMethod())) {
            //红人未入驻 且应收金额大于0
            if(NumberCst.ZERO.equals(excutionOrder.getInSystemAdmin()) && CommonUtil.greaterThanZero(calculationDevided.getAmountReceivable())) {
                if(IncomeContractTypeEnum.isFormalContract(incomeContract.getContractType())) {
                    //（收入合同后置）是否账号入驻为否时，生成一笔应收费用（费用类型：18形式合同费）
                    CfChargeCommonMessage formalReceivable = this.buildFomralReceivableFee(excutionOrder, incomeContract, calculationDevided, starBasicData);
                    chargeList.add(formalReceivable);
                } else if(IncomeContractTypeEnum.isLiveContract(incomeContract.getContractType()) && ObjectUtils.defaultIfNull(excutionOrder.getPlatformReport(), Boolean.FALSE).booleanValue()) {
                    //生成一笔 线上下单未入驻红人框架广告费
                    CfChargeCommonMessage onlineNoAdvertisingCharge = this.buildOnlineNoAdvertisingCharge(excutionOrder, incomeContract, calculationDevided, starBasicData);
                    chargeList.add(onlineNoAdvertisingCharge);
                }
            }
        }
        if(CollectionUtils.isNotEmpty(chargeList)) {
            //发送费用消息
            chargeList.forEach(charge -> {
                this.doSendRecordToMq(excutionOrder.getExcuteCode(), charge, this.financeTopic, "excutionOrder");
            });
        }
        if(CollectionUtils.isNotEmpty(invoiceList)) {
            //发送费用+账单消息
            invoiceList.forEach(invoice -> {
                this.doSendRecordToMq(excutionOrder.getExcuteCode(), invoice, this.financeTopic, "excutionOrder");
            });
        }
        //检查费用生成情况
        if(CollectionUtils.isNotEmpty(chargeList) ) {
            this.checkCharge(excutionOrder.getIncomeContractCode());
        }
        if(CollectionUtils.isNotEmpty(invoiceList) ) {
            this.checkCharge(excutionOrder.getExcuteCode());
        }
    }

    /**
     * 构建红人分成费
     * @param excutionOrder
     * @param incomeContract
     * @param calculationDevided
     * @return
     */
    private CfChargeCommonMessage buildStarDevidedFee(ContractExcutionOrder excutionOrder, IncomeContract incomeContract, CalculationDevided calculationDevided, StarBasicData starBasicData) {
        ExcutionOrderTypeEnum excutionOrderTypeEnum = ExcutionOrderTypeEnum.getByType(excutionOrder.getType());
        CfChargeCommonMessage chargeMessage = new CfChargeCommonMessage();
        chargeMessage.setChargeType(FinanceChargeTypeEnum.STAR_DEVIDED_CHARGE.getType());
        chargeMessage.setArapType(FinanceArapTypeEnum.PAY.getType());
        chargeMessage.setChargeSourceCode(excutionOrder.getExcuteCode());
        chargeMessage.setChargeSourceDetail(excutionOrder.getIncomeContractCode());
        chargeMessage.setBalance(starBasicData.getStarNickname());
        chargeMessage.setFinanceEntity(incomeContract.getCompanyContractSubject());
        chargeMessage.setTaxRate(BigDecimal.ZERO);
        chargeMessage.setCreateBy(excutionOrder.getExcutorId());
        chargeMessage.setCreateName(excutionOrder.getExcutorName());
        chargeMessage.setCreateDate(new Date());
        chargeMessage.setUpdateBy(chargeMessage.getCreateBy());
        chargeMessage.setUpdateDate(chargeMessage.getCreateDate());
        chargeMessage.setUpdateName(chargeMessage.getCreateName());
        chargeMessage.setTenantId(excutionOrder.getTenantId());
        chargeMessage.setCompanyId(excutionOrder.getCompanyId());
        switch (excutionOrderTypeEnum) {
            case INSIDE_EXCUTION_ORDER:
                chargeMessage.setSettTemplate(FinanceSettTemplateEnum.INSIDE_EXCUTION_ORDER_TEMPLATE.getType());
                break;
            case OUTSIDE_EXCUTION_ORDER:
            case KOC_EXCUTION_ORDER:
                chargeMessage.setSettTemplate(FinanceSettTemplateEnum.OUTSIDE_EXCUTION_ORDER_TEMPLATE.getType());
                break;
            default:
                break;
        }
        chargeMessage.setAmountPp(calculationDevided.getFinanceDevidedAmount());
        chargeMessage.setPricePp(chargeMessage.getAmountPp());
        chargeMessage.setAccountId(excutionOrder.getStarAccountInfoId());
        chargeMessage.setBalanceType(NumberCst.ONE);
        return chargeMessage;
    }

    /**
     * 构建红人采购费
     * @param excutionOrder
     * @param incomeContract
     * @param calculationDevided
     * @param starBasicData
     * @return
     */
    private CfChargeCommonMessage buildStarPurchaseFee(ContractExcutionOrder excutionOrder, IncomeContract incomeContract, CalculationDevided calculationDevided, StarBasicData starBasicData) {
        CfChargeCommonMessage chargeMessage = new CfChargeCommonMessage();
        chargeMessage.setChargeType(FinanceChargeTypeEnum.STAR_PURCHASE_CHARGE.getType());
        chargeMessage.setArapType(FinanceArapTypeEnum.PAY.getType());
        chargeMessage.setChargeSourceCode(excutionOrder.getExcuteCode());
        chargeMessage.setChargeSourceDetail(excutionOrder.getIncomeContractCode());
        chargeMessage.setAmountPp(calculationDevided.getFinanceDevidedAmount());
        chargeMessage.setPricePp(chargeMessage.getAmountPp());
        chargeMessage.setBalance(starBasicData.getStarNickname());
        chargeMessage.setFinanceEntity(incomeContract.getCompanyContractSubject());
        chargeMessage.setTaxRate(BigDecimal.ZERO);
        ExcutionOrderTypeEnum excutionOrderTypeEnum = ExcutionOrderTypeEnum.getByType(excutionOrder.getType());
        switch (excutionOrderTypeEnum) {
            case INSIDE_EXCUTION_ORDER:
                chargeMessage.setSettTemplate(FinanceSettTemplateEnum.INSIDE_EXCUTION_ORDER_TEMPLATE.getType());
                break;
            case OUTSIDE_EXCUTION_ORDER:
            case KOC_EXCUTION_ORDER:
                chargeMessage.setSettTemplate(FinanceSettTemplateEnum.OUTSIDE_EXCUTION_ORDER_TEMPLATE.getType());
                break;
            default:
                break;
        }
        /**
         * version:V1.16.1: 新增【财务信息ID+结算主体类型】
         */
        chargeMessage.setAccountId(excutionOrder.getStarAccountInfoId());
        chargeMessage.setBalanceType(NumberCst.ONE);
        return chargeMessage;
    }

    /**
     * 构建红人打款至红人应收费用
     * @param excutionOrder
     * @param incomeContract
     * @param calculationDevided
     * @return
     */
    private CfChargeCommonMessage buildFomralReceivableFee(ContractExcutionOrder excutionOrder, IncomeContract incomeContract, CalculationDevided calculationDevided, StarBasicData starBasicData) {

        CfChargeCommonMessage chargeMessage = new CfChargeCommonMessage();
        chargeMessage.setChargeType(FinanceChargeTypeEnum.NO_STAR_INCOME.getType());
        chargeMessage.setAccountId(null);
        chargeMessage.setBalance(starBasicData.getStarNickname());
        chargeMessage.setBalanceType(NumberCst.ONE);
        chargeMessage.setArapType(FinanceArapTypeEnum.RECEIVE.getType());
        chargeMessage.setChargeSourceCode(incomeContract.getContractCode());
        chargeMessage.setChargeSourceDetail(excutionOrder.getExcuteCode());
        chargeMessage.setChargeSourceDetail2(excutionOrder.getPlatformOrderCode());
        chargeMessage.setAmountPp(calculationDevided.getAmountReceivable());
        chargeMessage.setPricePp(calculationDevided.getAmountReceivable());

        chargeMessage.setFinanceEntity(incomeContract.getCompanyContractSubject());
        chargeMessage.setCreateBy(incomeContract.getCreateBy());
        chargeMessage.setCreateName(incomeContract.getCreateName());
        chargeMessage.setCreateDate(new Date());
        chargeMessage.setUpdateBy(incomeContract.getCreateBy());
        chargeMessage.setUpdateDate(chargeMessage.getCreateDate());
        chargeMessage.setUpdateName(incomeContract.getCreateName());
        chargeMessage.setTenantId(incomeContract.getTenantId());
        chargeMessage.setCompanyId(incomeContract.getCompanyId());
        chargeMessage.setSettTemplate(null);
        chargeMessage.setTaxRate(BigDecimal.ZERO);
        if (InvoiceFormEnum.NO_NEED_INVOICE.getType().equals(incomeContract.getInvoiceForm())) {
            chargeMessage.setAccountId(null);
        }
        return chargeMessage;
    }

    /**
     * 线上下单未入驻红人框架广告费
     * @param excutionOrder
     * @param incomeContract
     * @param calculationDevided
     * @return
     */
    private CfChargeCommonMessage buildOnlineNoAdvertisingCharge(ContractExcutionOrder excutionOrder, IncomeContract incomeContract, CalculationDevided calculationDevided, StarBasicData starBasicData) {
        CfChargeCommonMessage chargeMessage = new CfChargeCommonMessage();
        chargeMessage.setChargeType(FinanceChargeTypeEnum.NO_STAR_INCOME.getType());
        chargeMessage.setAccountId(null);
        chargeMessage.setBalance(starBasicData.getStarNickname());
        chargeMessage.setBalanceType(NumberCst.ONE);
        chargeMessage.setArapType(FinanceArapTypeEnum.RECEIVE.getType());
        chargeMessage.setChargeSourceCode(incomeContract.getContractCode());
        chargeMessage.setChargeSourceDetail(excutionOrder.getExcuteCode());
        chargeMessage.setChargeSourceDetail2(excutionOrder.getPlatformOrderCode());
        chargeMessage.setAmountPp(calculationDevided.getAmountReceivable());
        chargeMessage.setPricePp(calculationDevided.getAmountReceivable());

        chargeMessage.setFinanceEntity(incomeContract.getCompanyContractSubject());
        chargeMessage.setCreateBy(incomeContract.getCreateBy());
        chargeMessage.setCreateName(incomeContract.getCreateName());
        chargeMessage.setCreateDate(new Date());
        chargeMessage.setUpdateBy(incomeContract.getCreateBy());
        chargeMessage.setUpdateDate(chargeMessage.getCreateDate());
        chargeMessage.setUpdateName(incomeContract.getCreateName());
        chargeMessage.setTenantId(incomeContract.getTenantId());
        chargeMessage.setCompanyId(incomeContract.getCompanyId());
        chargeMessage.setSettTemplate(null);
        chargeMessage.setTaxRate(BigDecimal.ZERO);
        if (InvoiceFormEnum.NO_NEED_INVOICE.getType().equals(incomeContract.getInvoiceForm())) {
            chargeMessage.setAccountId(null);
        }
        return chargeMessage;
    }

    /**
     * 填充数据域信息
     * @param message
     * @param excutionOrder
     * @param userMapping
     */
    private void fillDataScopeInfo(CfChargeCommonMessage message, ContractExcutionOrder excutionOrder, Map<String, SUserVo> userMapping) {
        message.setCreateBy(excutionOrder.getExcutorId());
        message.setCreateName(excutionOrder.getExcutorName());
        message.setCreateDate(new Date());
        message.setUpdateBy(message.getCreateBy());
        message.setUpdateName(message.getCreateName());
        message.setUpdateDate(message.getCreateDate());
        SUserVo sUserVo = userMapping.get(excutionOrder.getExcutorName());
        if(Objects.nonNull(sUserVo)) {
            message.setTenantId(sUserVo.getTenantId());
            message.setCompanyId(sUserVo.getCompanyId());
            message.setDepartmentId(sUserVo.getDepartmentId());
        }
    }

    /**
     * 构建自动生成账单报文
     * @param excutionOrder
     * @param chargeMessage
     * @return
     */
    private ChargeAutoInvoiceMessage buildAutoInvoiceMessage(ContractExcutionOrder excutionOrder, CfChargeCommonMessage chargeMessage) {
        ChargeAutoInvoiceMessage message = new ChargeAutoInvoiceMessage();
        //业务类型：1-货品采购; 2-销售订单; 3-MCN; 4-WMS
        message.setChargeSourceType(3);
        message.setChargeInfos(Lists.newArrayList(chargeMessage));
//        message.setAccountId(excutionOrder.getAccountId());
//        message.setAccountType(excutionOrder.getAccountType());
//        message.setAccountName(excutionOrder.getPaidWay());
//        message.setCustomerInvoiceWay(excutionOrder.getCustomerInvoiceWay());
        message.setCreateBy(chargeMessage.getCreateBy());
        message.setCreateName(chargeMessage.getCreateName());
        message.setCreateDate(chargeMessage.getCreateDate());
        message.setUpdateBy(chargeMessage.getUpdateBy());
        message.setUpdateName(chargeMessage.getUpdateName());
        message.setUpdateDate(chargeMessage.getUpdateDate());
        message.setTenantId(chargeMessage.getTenantId());
        message.setCompanyId(chargeMessage.getCompanyId());
        message.setDepartmentId(chargeMessage.getDepartmentId());
        return message;
    }
}
